﻿/*----------------------------------------------------------------
//  <copyright file="EntityEntryProvider.cs" company="MicroCloud@151504200868">
//      Copyright © 2020-2024 MicroCloud Corporation, All rights reserved.
//  </copyright>
//  <site>https://gitee.com/chenmm123/microclouds</site>
//  <last-editor>cmm</last-editor>
//  <last-date>2023-12-06 10:54</last-date>
//----------------------------------------------------------------*/

namespace MicroCloud.Events
{
    #region "实体条目事件信息提供者"
    /// <summary>
    /// 实体条目事件信息提供者
    /// </summary>
    public class EntityEntryProvider : IEntityEntryProvider
    {
        //字段
        private readonly IEntityInfoHandler _entityInfoHandler;
        private readonly ILogger _logger;

        #region "构造函数"
        #region "初始化一个实体条目事件信息提供者的新实例"
        /// <summary>
        /// 初始化一个实体条目事件信息提供者 <see cref="EntityEntryProvider"/> 的新实例
        /// </summary>
        /// <param name="provider">服务提供者</param>
        public EntityEntryProvider(IServiceProvider provider)
        {
            _logger = provider.GetLogger(this);
            _entityInfoHandler = provider.GetService<IEntityInfoHandler>();
        }
        #endregion

        #endregion

        #region "方法"
        #region "从指定上下文中获取实体条目"
        /// <summary>
        /// 从指定上下文中获取实体条目
        /// </summary>
        /// <param name="context">数据上下文</param>
        /// <returns>实体条目集合</returns>
        public virtual List<EntityEntry> GetEntityEntries(DbContext context)
        {
            List<EntityEntry> result = new();
            if (_entityInfoHandler == null)
            {
                return result;
            }

            EntityState[] states = { EntityState.Added, EntityState.Modified, EntityState.Deleted };
            var entries = context.ChangeTracker.Entries().Where(m => m.Entity != null && states.Contains(m.State)).ToList();
            if (entries.Count == 0)
            {
                return result;
            }

            foreach (var entry in entries)
            {
                var entityType = entry.Entity.GetType();

                IEntityInfo entityInfo = _entityInfoHandler.GetEntityInfo(entityType);
                if (entityInfo == null)
                {
                    continue;
                }

                if (!entityInfo.EventEnabled)
                {
                    _logger.LogDebug("提取数据操作：实体 {entityInfo} 未开启数据事件，跳过。", entityInfo);
                    continue;
                }

                if (entityType.HasAttribute<EventEntityIgnoreAttribute>())
                {
                    _logger.LogDebug("提取数据操作：实体 {entityInfo} 设置了忽略数据事件，跳过。", entityInfo);
                    continue;
                }

                var primaryKeyProperty = entry.CurrentValues.Properties.FirstOrDefault(o => o.IsPrimaryKey());
                var entityKeyProperty = entry.Property(primaryKeyProperty.Name);
                var contextEntityType = context.Model.FindEntityType(entityType) ?? context.Model.FindEntityType(entityType.BaseType);
                EntityEntry entityEntry = new()
                {
                    EntityName = entityInfo.Name,
                    EntityTypeName = entityInfo.TypeName,
                    OperateType = entry.State == EntityState.Added
                    ? OperateType.Insert
                    : entry.State == EntityState.Modified
                        ? OperateType.Update
                        : entry.State == EntityState.Deleted
                            ? OperateType.Delete
                            : OperateType.Query,
                    DbSchema = contextEntityType.GetSchema(),
                    DbObjName = contextEntityType.GetTableName(),
                    DbObjType = DatabaseObjectType.Table,
                    KeyField = primaryKeyProperty.Name,
                    KeyValue = entry.State == EntityState.Deleted
                        ? entityKeyProperty.OriginalValue?.ToString()
                        : entityKeyProperty.CurrentValue?.ToString(),
                    Entity = entry.Entity
                };

                result.AddIfNotNull(entityEntry);
                _logger.LogDebug("提取数据操作：实体 {entityInfo}。", entityInfo);
            }

            return result;
        }
        #endregion

        #endregion

    }
    #endregion

}
